JWT 検証ライブラリ
google-auth-library #Node Google の署名を楽に検証する
鍵をインスタンスキャッシュしてるが、format 変われば使い回されない
code:verify-google-auth-librar.ts
import { OAuth2Client, LoginTicket, TokenPayload } from 'google-auth-library';
const authClient = new OAuth2Client();
const bearer = req.header('Authorization') || '';
const token = bearer.split('Bearer ');
authClient.verifyIdToken({
idToken: token,
audience: options.audience,
}).then((ticket: LoginTicket) => {
const claims = ticket.getPayload();
...
});
こういう Express middleware を作っておくと楽
code:express-verify-middleware.ts
import { OAuth2Client, LoginTicket, TokenPayload } from 'google-auth-library';
import createError = require('http-errors');
import { Request, Response, NextFunction } from 'express';
export interface RequestWithClaims extends Request {
claims: TokenPayload | undefined;
}
interface Options {
email: string;
audience: string;
}
export function verify(options: Options) {
const authClient = new OAuth2Client();
return (req: Request, res: Response, next: NextFunction) => {
const bearer = req.header('Authorization') || '';
const token = bearer.split('Bearer ');
authClient
.verifyIdToken({
idToken: token,
audience: options.audience,
})
.then((ticket: LoginTicket) => {
const claims = ticket.getPayload();
(req as RequestWithClaims).claims = claims;
if (options.email !== claims?.email) {
throw new Error(Unexpected email ${claims?.email});
}
next();
})
.catch(err => next(createError(403, err)));
};
decode
jwt.decode(token) は payload だけ
jwt.decode(token, { complete: true }) は { header, payload, signature } を返す
verify
第二引数に鍵をフェッチする callback を渡せる
deprecated なのだがこれを渋々使う?
github.com/lestrrat/go-jwx
jws.VerifyWithJKU で JWK フェッチしつつ検証できるがキャッシュ機構はないので、頻度低い検証用途
jwk.Fetch で取得した keset をキャッシュしておいて jws.VerifyWithJWKSet を使うのがいいかな
jwk.Set からトークン中の kid をもとに使う key を選ぶのでなく、Set 中の鍵を順番に試す実装
code:jws_verify.go
payload, err := jws.VerifyWithJWKSet([]byte(tokenString), set, nil)
if err != nil {
log.Fatalf("%+v", err)
}
fmt.Printf("%+v\n", string(payload))
楽だけど未知の kid が出てきたら fetch しなおしたい kid ごとにキャッシュしたい、という場合は使いづらい
メッセージの header から kid を取り出してほしくなさそうな実装
refresh されうる複数の公開鍵をキャッシュしつつ使う、というときに噛みわない
まあこういう感じに組み合わせると楽だけども...
github.com/dgrijalva/jwt-go は jwk 便利グッズがないので、組み合わせるのがいいかな
自前 or github.com/dgrijalva/jwt-go で header から kid を抜き出す
jwk.Fetch で取得したものをまるごと or kid ごとにキャッシュ
set.LookupKeyID(kid) で探す or kid ごとに引いて verify